Welcome.
In this lecture, we're going to take a closer look at meta tables and meta methods to make sure you
understand everything.
So let's just jump right into it.
I'm first going to create a class for us.
We're just going to call it bank account.
This is going to be our bank account class.
And what is the bank account need.
Well a bank account needs an owner right.
Who owns the bank account?
The bank account needs a value.
How much money is stored in it.
And then we'll also need a Pin for the bank account.
This table is going to act as our class and our meta table for any future bank account objects.
Now, what are some functions that our bank account needs?
Well, to create a new bank account of course we're going to need a new constructor.
So if we ever want to create a new bank account, we'll have to pass an owner to this function.
However much money we want to start by putting into our bank account, and then the pin to set for our
bank account.
We also need some functions that the bank account can use, such as depositing into our bank account.
It may be a function to withdraw from our bank account.
And with these functions, we can pass the amount we want to deposit as well as the pin required.
And then we can do the same thing for withdrawing as well.
So inside of our constructor, what we could do is we could create a new variable called self, and
it'll be equal to the set Metatable function.
We'll create a new table and attach the bank account as the meta table.
Now in order for us to access the values that we put in here originally, these properties here, as
well as the functions that are a part of the bank account, we have to set a meta method inside of the
bank account the index meta method.
So bank account dot underscore underscore index is equal to the bank account.
That way whenever I let's say index this table here it's going to check to see hey we've got a bank
account meta method.
And let's see if that index belongs to this meta method.
If it does like deposit or the owner or the value or the pin, then it'll be good to go.
So this section we can call here for our meta methods.
Now that we have this done, we can now access things like the value, the owner and the pin for this
new bank account so we can set the owner equal to the owner that is passed to the function.
We can set the value equal to the value passed to this function.
And we can set the pin to the pin that is passed to this function.
Then we just need to return this new table back to where this function was called.
Now we are able to create new bank account objects.
So if I go down here I can create a new account.
I'll just call this account one equal to bank account dot new.
Let's say the owner is Bob.
Bob wants to put $100 into his bank account.
And his pin will be one, two, three, four.
So now we have a new bank account object and we can do another bank account object.
We'll call this account two.
We'll have a bank account new, and we'll have Jim be the owner of this bank account.
He puts in $500 and he has a pin of four, three, two, one.
Now, let's say I wanted to add these bank accounts together.
Let's say remove value from one bank account and put it into the other one.
So for example, in our first bank account, maybe I want to add the value that is inside of Jim's bank
account account two.
How could I add the value of this bank account, which is 500, and put it in this bank account, which
has a value of 600, meaning we would subtract 500 from this bank account, making it zero, and add
500 to this bank account, making it 600 just by using the addition operator.
Well, this is where the add meta method comes into play.
What we could do for our bank account.
We can set the underscore underscore add meta method equal to a new function.
And this add meta method automatically passes two arguments to our function.
One is the first object we're trying to add to, and then the second object is the other object we want
to add to the first object.
So we can call this adding.
Now, the first thing that I want to make sure of is that this thing that I'm trying to add to my table
is also another bank account object.
But how would I be able to differentiate this table from, let's say, other tables that are in my game?
Well, what we could do for the bank account is we could add another property.
And we could call it underscore, underscore type and set it to some unique type for our bank account.
So let's say this is the type of bank account.
This isn't an actual meta method, but we can just assume it is.
And it's going to store the bank account type for us.
So what we could do is we need to first verify that adding is not null.
Because let's say I tried to do this, it would error, but I want to avoid that error.
So we're going to have to make a check for it.
So we can say if not adding.
So if the value of adding is false.
Or we could check if the type of adding.
Is not equal to the type of table.
And what we could do is we could raise an error and we could say, attempt to add type and we'll concatenate
it with the type of this adding.
And we'll say attempt to add this type to type.
And then we can do self dot underscore underscore type which will reference the type right here.
That is part of the bank account class.
So it'll so if this um so let's say adding was nil.
If it was nil then this would print attempt to add type nil to type bank account.
The next thing we can check for is whether or not the type of this table is a bank account.
So if the adding dot underscore underscore type is not equal to bank account.
Then we can return self and end, and we'll actually need to do that right here as well.
Now we have to make sure we return self, because when we call this addition operator, it's attempting
to create or store a new variable on our account, one which is going to be different from the original.
And we need so we have to return self back to where this function was called.
Otherwise it's not going to work and we won't be able to add any amount to our table.
But once we verify that, what we're trying to add to this table is a table and it is a bank account.
What we could do now.
Is we could use the deposit and withdrawal functions to our advantage.
So for the adding bank account, what we could do is we could withdraw, um, the amount that is inside
of this table.
So adding dot value.
And we'll also make sure to pass the pin to verify, you know, this is the bank account's owner or
whatever.
We could withdraw it from that, and then we could deposit it into the original table using self deposit.
But then the issue here is, how are we going to know the exact amount of adding value?
Because when we withdraw it, it's going to subtract from it.
And we need to set that amount in the deposit well inside of these functions.
What we could do is we could first check if the pin passed to this function is not equal to the pin
of the bank account, then we're just going to return false, meaning the deposit failed.
And then I'm going to return a number which signifies how much money was deposited or withdrawn.
In this case it would be zero because we failed.
We could also check if the amount that they're attempting to deposit into the account is negative for
some reason.
So if the amount is less than or let's say it's equal to zero.
So if it's zero or less, then we're also going to return false and zero and end.
Otherwise if all checks out then we can set self dot value plus equal the amount.
And then we can return true.
We successfully added this amount and returned the amount we added or deposited into the bank account.
And again, remember we have access to self here is because we're using a cone.
So whenever we call this function directly on a bank account table, the table automatically gets passed
to this function as self.
And then we can basically just copy this and do the same thing here.
But instead what we're going to do.
Is we're going to make a variable, I'll call it amount can withdraw and it's going to be equal to math
dot min.
And we'll pass self dot value and the amount.
So let's say for some reason.
The amount we were trying to withdraw is greater than the amount of money that we already have in the
bank account.
So let's say this was 50 and we only had $10 in our bank account.
Well, this function is going to return to us the smallest number out of the list of numbers we give
to it, which in this case would be $10, because that's all we can withdraw.
And we want to be able to withdraw $50.
So once we get that correct number then we can set self dot value minus equal amount can withdraw and
we return true and we return the amount that we withdrew.
Great.
So now we can go back here.
And what we could do is we could store the result from this function into two variables.
Um, I'm not going to need the first one, but I will need the second one, which will be the amount
that we withdrew out of this account.
And then we can deposit this amount into the original table.
And pass the pen for this table as well.
And then last but not least, we have to make sure to return self at the very end.
So what we've done now is that whenever we attempt to add two bank accounts together, just like this.
It's going to call this ad meta method.
It's going to pass the first table, which is account one, and pass the second table which is account
two.
It's going to make sure that the second table is a table and that it's a type of bank account.
When it is then we're going to withdraw however much money we can out of the second bank account.
And we're going to take that amount and deposit within the original bank account.
That's all we're doing here.
So that means after I add the amount of money that is in account two, to account one, this should
be $600 and our account two should be $0.
So let's find out.
Let's print account one dot value.
And then we can also print account two dot value.
And then we can go and run our game and see what gets printed in the console.
And there we go.
Just like that, we got $600 in our first bank account, and now we have zero in the second bank account.
Pretty neat.
Well, let's say I wanted to subtract the bank accounts.
So let's say I wanted to subtract money, however much I could out of this bank account and put it into
the second bank account.
Well, we have another meta method for that.
And that meta method is called.
Underscore underscore sub short for subtraction.
And again we'll need a function for this.
And it passes the first table we want to subtract from.
And then it also passes us the second table.
We'll call it removing which we want to take out of this.
And I guess we could put it into this bank account.
So what we could do is we could copy the same thing here.
Right.
We want to make sure that the second thing we're trying to subtract from the original table is a table,
and that it's a bank account.
So I'm going to replace these references.
And then what I need to do is I need to call the withdraw function on self.
And I need to withdraw however much money I can.
In this case, I want to withdraw the removing dot value and then we'll make sure to pass self dot pin.
Now we need to store whether or not this withdraw was successful or not.
So success.
And then the amount.
Because let's say the second table had $500.
I wanted to subtract from a table that only had $100.
That means I withdraw would fail, right?
In the case that our withdrawal fails.
So if not successful.
What we could do is the same thing set success amount equal to self withdraw and instead we'll just
withdraw whatever money we have within this bank account.
So dot value.
So we are withdrawing all the money that we can out of self make sure to pass the pin.
And once that's done, then we can go ahead and deposit that money into the second table or the removing
table.
So deposit.
This amount and pass the pin as well.
Otherwise, if we were successful in withdrawing the money, then we can just do the exact same thing
here as well.
And actually, there's a better way to format our code where we don't have to have these two same lines
doing the exact same thing.
What we could do is we could just have one of those lines.
So this if statement will just check if we weren't successful, if we were not successful, then it
updates these variables.
And then once the variable gets updated, then we deposit the correct amount into that second table.
So that means because I changed this to subtraction, what's going to happen is it's going to take the
$100 from this account and put it into our second account.
So the first account should be zero and the second account should be 600.
It should flip.
So let's run and find out.
And we get an error attempt to index nil with value.
Oh, and the reason it did that?
Ha ha!
We have to make sure to return self at the end here, because if we don't return self, it's not going
to know what to update account one with and it's just going to set it to nil.
So this is why we have to return self here.
Otherwise it's going to end up as nil.
So we got that fixed.
We're going to save that and let's run it again.
Should be there we go zero 600.
So we've subtracted however much money we could out of the first account and placed it into the second
account.
Now, if I updated the money in the second account to only be $50, then what should happen is that
it should subtract $50 from the first account and make this account $100.
So let's run it.
And there we go, $50 in the first account, $100 in the second account.
So as you can see, this is how we can use tables and meta tables to imitate classes in Lua.
We can also take all this functionality and store it in a different script, which would be our module
script.
So let's actually do that real quick.
I'm going to go into server storage, and I actually already have a folder in here called classes.
And what I'm going to do is I'm going to create a new module script in here.
And this is going to be my bank account class.
And because a module script returns a table, we can literally just use the table that we declared right
here as the table to return in this module script.
So actually let's go and copy all of this functionality.
And we can delete this.
And at the very end of our module script we can just return the bank account table.
So now whenever we require this module script from a script in our server, we can get this bank account
class.
And then we can use the bank account new function to create new bank account objects.
And we can use the same deposit and withdrawal functions.
And we can use the same subtraction and addition meta methods that are inside of our bank account class.
So this is kind of the core essential idea of meta methods and meta tables as classes in Lua.
In the next lectures, we're going to go ahead and move forward into some other territory in object
oriented programming such as inheritance, polymorphism, abstraction, and a bunch of other neat stuff.
So I hope to see you there.